import { NestFactory } from '@nestjs/core';
import { ValidationPipe, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { IoAdapter } from '@nestjs/platform-socket.io';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
import * as compression from 'compression';
import helmet from 'helmet';
import * as cookieParser from 'cookie-parser';
import { AppModule } from './app.module';

async function bootstrap() {
  const logger = new Logger('Bootstrap');

  // 创建应用实例
  const app = await NestFactory.create<NestExpressApplication>(AppModule, {
    logger: ['error', 'warn', 'log', 'debug', 'verbose'],
    cors: true,
  });

  // 获取配置服务
  const configService = app.get(ConfigService);
  const port = configService.get('app.port', 3000);
  const apiPrefix = configService.get('app.apiPrefix', 'api');
  const env = configService.get('app.env', 'development');

  // 设置全局前缀
  app.setGlobalPrefix(apiPrefix);

  // 安全中间件
  app.use(
    helmet({
      contentSecurityPolicy: {
        directives: {
          defaultSrc: ["'self'"],
          styleSrc: ["'self'", "'unsafe-inline'"],
          scriptSrc: ["'self'"],
          imgSrc: ["'self'", 'data:', 'https:'],
          connectSrc: ["'self'", 'ws:', 'wss:'],
        },
      },
      crossOriginEmbedderPolicy: false,
    }),
  );

  // 压缩中间件
  app.use(compression());

  // Cookie解析器
  app.use(cookieParser());

  // 静态文件服务
  app.useStaticAssets(join(__dirname, '..', 'public'), {
    prefix: '/static/',
  });

  // CORS配置
  app.enableCors({
    origin: configService.get('app.cors.origin', '*'),
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
    allowedHeaders: [
      'Origin',
      'X-Requested-With',
      'Content-Type',
      'Accept',
      'Authorization',
      'X-Access-Token',
      'X-API-Key',
    ],
    credentials: configService.get('app.cors.credentials', true),
    maxAge: 86400, // 24小时
  });

  // 全局验证管道
  app.useGlobalPipes(
    new ValidationPipe({
      transform: true,
      whitelist: true,
      forbidNonWhitelisted: true,
      skipMissingProperties: false,
      skipNullProperties: false,
      skipUndefinedProperties: false,
      errorHttpStatusCode: 422,
      exceptionFactory: errors => {
        const messages = errors
          .map(error => {
            const constraints = error.constraints;
            return constraints ? Object.values(constraints).join(', ') : '';
          })
          .filter(Boolean);

        return {
          statusCode: 422,
          message: '数据验证失败',
          errors: messages,
          timestamp: new Date().toISOString(),
        };
      },
    }),
  );

  // WebSocket适配器
  app.useWebSocketAdapter(new IoAdapter(app));

  // Swagger文档配置
  if (env === 'development' || env === 'staging') {
    const config = new DocumentBuilder()
      .setTitle('FaceTime Backend API')
      .setDescription('视频通话应用后端API文档')
      .setVersion('1.0.0')
      .setContact(
        'API Support',
        'https://github.com/your-repo',
        'support@example.com',
      )
      .setLicense('MIT', 'https://opensource.org/licenses/MIT')
      .addServer(`http://localhost:${port}`, '本地开发服务器')
      .addServer('https://api.example.com', '生产服务器')
      .addBearerAuth(
        {
          type: 'http',
          scheme: 'bearer',
          bearerFormat: 'JWT',
          name: 'JWT',
          description: 'Enter JWT token',
          in: 'header',
        },
        'JWT-auth',
      )
      .addApiKey(
        {
          type: 'apiKey',
          name: 'X-API-Key',
          in: 'header',
          description: 'API密钥认证',
        },
        'API-Key',
      )
      .addTag('应用', '应用基本信息接口')
      .addTag('房间', '房间管理接口')
      .addTag('健康检查', '系统健康检查接口')
      .addTag('WebSocket', 'WebSocket实时通信接口')
      .build();

    const document = SwaggerModule.createDocument(app, config, {
      operationIdFactory: (controllerKey: string, methodKey: string) =>
        methodKey,
      deepScanRoutes: true,
    });

    SwaggerModule.setup(`${apiPrefix}/docs`, app, document, {
      swaggerOptions: {
        persistAuthorization: true,
        displayRequestDuration: true,
        docExpansion: 'none',
        filter: true,
        showRequestHeaders: true,
        tryItOutEnabled: true,
      },
      customSiteTitle: 'FaceTime API Documentation',
      customfavIcon: '/static/favicon.ico',
      customCss: `
        .swagger-ui .topbar { display: none }
        .swagger-ui .info { margin: 20px 0 }
        .swagger-ui .scheme-container { margin: 20px 0 }
      `,
    });

    logger.log(
      `📚 Swagger文档已启用: http://localhost:${port}/${apiPrefix}/docs`,
    );
  }

  // 优雅关闭处理
  process.on('SIGTERM', async () => {
    logger.log('收到SIGTERM信号，开始优雅关闭...');
    await app.close();
    process.exit(0);
  });

  process.on('SIGINT', async () => {
    logger.log('收到SIGINT信号，开始优雅关闭...');
    await app.close();
    process.exit(0);
  });

  // 未捕获异常处理
  process.on('uncaughtException', error => {
    logger.error('未捕获的异常:', error);
    process.exit(1);
  });

  process.on('unhandledRejection', (reason, promise) => {
    logger.error('未处理的Promise拒绝:', reason);
    logger.error('Promise:', promise);
  });

  // 启动应用
  await app.listen(port, '0.0.0.0');

  logger.log(`🚀 应用已启动`);
  logger.log(`🌍 环境: ${env}`);
  logger.log(`🔗 HTTP服务: http://localhost:${port}`);
  logger.log(`📡 API接口: http://localhost:${port}/${apiPrefix}`);

  if (env === 'development' || env === 'staging') {
    logger.log(`📚 API文档: http://localhost:${port}/${apiPrefix}/docs`);
  }

  logger.log(
    `💾 数据库: ${configService.get('database.type')}://${configService.get('database.host')}:${configService.get('database.port')}/${configService.get('database.database')}`,
  );
  logger.log(
    `🔴 Redis: ${configService.get('redis.host')}:${configService.get('redis.port')}/${configService.get('redis.db')}`,
  );
  logger.log(
    `🎯 WebSocket端口: ${configService.get('app.websocket.port', 3001)}`,
  );
}

bootstrap().catch(error => {
  const logger = new Logger('Bootstrap');
  logger.error('应用启动失败:', error);
  process.exit(1);
});
